﻿using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Linq;
using System.Threading;
using Cubicle.Core.Interfaces;
using Cubicle.Core.Shared;

namespace Cubicle.Core.Processors.Logging
{

    public static class LoggingExtensions
    {
        
        public static void UpdateProgress(this Thread thread, double progress)
        {
            var request = InstructionLogger.GetRequest(thread);
            if  (request == null) return;
            request.Progress(progress);
        }

        public static double GetProgress(this Thread thread)
        {
            var request = InstructionLogger.GetRequest(thread);
            return request == null 
                ? -1 
                : request.Progress();
        }
    }

    [Export(typeof(IProcessor))]
    [ExportMetadata("Name", "InstructionLogger")]
    [ExportMetadata("Description", "A pass-through processor that keeps a log of all instructions.")]
    public class InstructionLogger : InstructionRequestProcessor
    {
        private const int DefaultCapacity = 10000;

        public static SortedList<int, InstructionRequest> History { get; set; }

        public static InstructionRequest GetRequest(Thread t)
        {
            return History
                .Values
                .Where(r => r.ExecutingThread == t)
                .FirstOrDefault();
        }

        public int Capacity { get; set; }

        public InstructionLogger() : base(RequestType.AllIncoming) {}
        public InstructionLogger(
            RequestType filter = RequestType.AllIncoming,
            int capacity = DefaultCapacity)
            : base(filter)
        {
            Capacity = capacity;
            History = new SortedList<int, InstructionRequest>(capacity);
        }

        public bool StopInstruction(int i)
        {
            if (!History.ContainsKey(i)) return false;
            if (History[i].Inst.EndTime != DateTime.MaxValue) return false;
            if (History[i].ExecutingThread == null) return false;
            History[i].ExecutingThread.Join();
            return true;
        }

        public SortedList<int, InstructionRequest> GetInstructionLog()
        {
            return History;
        }

        public Dictionary<int, string> GetExecutingInstructions()
        {
            return History
                .Where(x => x.Value.Inst.EndTime == DateTime.MaxValue)
                .ToDictionary(x => x.Key, x => Helpers.DataContractToString(x.Value));
        }

        public Dictionary<int, string> GetInstuctionHistory()
        {
            return History
                .ToDictionary(x => x.Key, x => Helpers.DataContractToString(x.Value));
        }

        #region Overrides of ConditionalProcessor<InstructionRequest>

        public override InstructionRequest ConditionalProcess(InstructionRequest request)
        {
            // Truncate log if it's at capacity
            if (History.Count == Capacity) History.RemoveAt(0);

            // Add new item
            History.Add(request.Id, request);

            return request;
        }

        #endregion
    }
}
